package io.github.wanggit.antrpc.gateway.starter.listeners;

import io.github.wanggit.antrpc.commons.bean.*;
import io.github.wanggit.antrpc.commons.constants.ConstantValues;
import io.github.wanggit.antrpc.commons.utils.JsonUtils;
import io.github.wanggit.antrpc.commons.zookeeper.ZkNodeType;
import io.github.wanggit.antrpc.gateway.starter.containers.IHttpUrlContainer;
import io.github.wanggit.antrpc.gateway.starter.zk.IZkClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent.Type;

import java.util.Map;

@Slf4j
public class RegisterNodeListener implements IListener {

    private final IZkClient zkClient;

    private final IHttpUrlContainer httpUrlContainer;

    public RegisterNodeListener(IZkClient zkClient, IHttpUrlContainer httpUrlContainer) {
        this.zkClient = zkClient;
        this.httpUrlContainer = httpUrlContainer;
    }

    @Override
    public void listen() {
        TreeCache rootNodeTreeCache =
                new TreeCache(zkClient.getCurator(), "/" + ConstantValues.ZK_ROOT_NODE_NAME);
        rootNodeTreeCache
                .getListenable()
                .addListener(
                        ((client, event) -> {
                            doEvent(event);
                        }));
    }

    private void doEvent(TreeCacheEvent event) {
        ChildData data = event.getData();
        ZkNodeType.RegisterNodeType registerNodeType =
                ZkNodeType.getRegisterNodeType(data.getPath());
        if (ZkNodeType.RegisterNodeType.INTERFACE.equals(registerNodeType)) {
            InterfaceNodeDataBean interfaceNodeDataBean =
                    JsonUtils.fromJson(event.getData().getData(), InterfaceNodeDataBean.class);
            HttpBean httpBean = interfaceNodeDataBean.getHttpBean();
            if (log.isDebugEnabled()) {
                log.debug(
                        "Listen: "
                                + event.getData().getPath()
                                + " "
                                + event.getType().name()
                                + " httpBean="
                                + (null == httpBean ? null : JsonUtils.toJsonString(httpBean)));
            }
            if (null != httpBean) {
                Map<String, RegisterBeanMethod> methodMap = interfaceNodeDataBean.getMethodMap();
                if (null != methodMap) {
                    methodMap.forEach(
                            (key, value) -> {
                                GetBean getBean = value.getGetBean();
                                PostBean postBean = value.getPostBean();
                                if (null != getBean) {
                                    // 添加Get方法
                                    doSomethingWithGet(
                                            event,
                                            httpBean,
                                            getBean,
                                            interfaceNodeDataBean.getAppName());
                                }
                                if (null != postBean) {
                                    doSomethingWithPost(
                                            event,
                                            httpBean,
                                            postBean,
                                            interfaceNodeDataBean.getAppName());
                                }
                            });
                }
            }
        }
    }

    private void doSomethingWithPost(
            TreeCacheEvent event, HttpBean httpBean, PostBean postBean, String appName) {
        if (Type.NODE_ADDED.equals(event.getType())) {
            httpUrlContainer.add(httpBean, postBean, appName);
        } else if (Type.NODE_UPDATED.equals(event.getType())) {
            httpUrlContainer.update(httpBean, postBean, appName);
        } else if (Type.NODE_REMOVED.equals(event.getType())) {
            httpUrlContainer.remove(httpBean, postBean, appName);
        }
    }

    private void doSomethingWithGet(
            TreeCacheEvent event, HttpBean httpBean, GetBean getBean, String appName) {
        if (Type.NODE_ADDED.equals(event.getType())) {
            httpUrlContainer.add(httpBean, getBean, appName);
        } else if (Type.NODE_UPDATED.equals(event.getType())) {
            httpUrlContainer.update(httpBean, getBean, appName);
        } else if (Type.NODE_REMOVED.equals(event.getType())) {
            httpUrlContainer.remove(httpBean, getBean, appName);
        }
    }
}
